﻿#light

// "AbstractProductA"
type Herbivore =
    interface
    end

// "AbstractProductB"
type Carnivore =
    abstract Eat : Herbivore -> unit

// "ProductA1"
type Wildebeest() =
    interface Herbivore

// "ProductB1"
type Lion() =
    interface Carnivore with
        member this.Eat(h) =
            // Eat Herbivore
            printfn "%s eats %s" (this.GetType().Name) (h.GetType().Name)

// "ProductA2"
type Bison() =
    interface Herbivore

// "ProductB2"
type Wolf() =
    interface Carnivore with
        member this.Eat(h) =
            // Eat Herbivore
            printfn "%s eats %s" (this.GetType().Name) (h.GetType().Name)

// "AbstractFactory"
type ContinentFactory =
    abstract CreateHerbivore : unit -> Herbivore
    abstract CreateCarnivore : unit -> Carnivore

// "ConcreteFactory1"
type AfricaFactory() =
    interface ContinentFactory with
        member this.CreateHerbivore() =
            Wildebeest() :> Herbivore

        member this.CreateCarnivore() =
            Lion() :> Carnivore

// "ConcreteFactory2"
type AmericaFactory() =
    interface ContinentFactory with
        member this.CreateHerbivore() =
            Bison() :> Herbivore

        member this.CreateCarnivore() =
            Wolf() :> Carnivore

// "Client"
type AnimalWorld(factory: ContinentFactory) =
    let h = factory.CreateHerbivore()
    let c = factory.CreateCarnivore()

    member this.RunFoodChain() =
        c.Eat(h)
